package com.lmxdawn.api.common.session;

import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.lmxdawn.api.common.exception.NotPermissionException;
import com.lmxdawn.api.dnf.annotation.Permission;
import com.lmxdawn.api.dnf.service.IAuthorization;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.AsyncHandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

/**
 * 权限拦截器（必须在 SessionInterceptor 拦截器之后执行）
 *
 * @author jy
 * @since 2023-12-04 16:54
 */
@Slf4j
@Setter
public class PermissionInterceptor implements AsyncHandlerInterceptor {
    
    /**
     * 无注解情况下，设置为true，不进行权限验证
     */
    private boolean nothingAnnotationPass = true;
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        if (handler instanceof HandlerMethod) {
            if (!SessionContextHolder.isLogin()) {
                return true;
            }
            // 权限验证合法
            if (isVerification(request, handler, SessionContextHolder.get())) {
                return true;
            }
            // 无权限访问
            log.debug("request 403 url: {}", request.getRequestURI());
            throw new NotPermissionException();
        }
        return true;
    }
    
    /**
     * <p>
     * 判断权限是否合法，支持 1、请求地址 2、注解编码
     * </p>
     *
     */
    protected boolean isVerification(HttpServletRequest request, Object handler, UserSession userSession) {
        // 注解权限认证
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        Permission pm = method.getAnnotation(Permission.class);
        if (pm != null) {
            if (pm.ignore()) {
                // 忽略拦截
                return true;
            } else if (!StringPool.EMPTY.equals(pm.value()) && this.getAuthorization()
                    .isPermitted(userSession, pm.value())) {
                // 权限合法
                return true;
            }
        } else if (nothingAnnotationPass) {
            // 无注解情况下，设置为true，不进行期限验证
            return true;
        }
        // 非法访问
        return false;
    }

    private IAuthorization getAuthorization() {
        return SpringUtil.getBean(IAuthorization.class);
    }
    
}
